/* 部分参考contiki
 * Copyright (c) 2005, Swedish Institute of Computer Science
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file is part of the Contiki operating system.
 *
 */
#ifndef __COROUTINE_H__
#define __COROUTINE_H__

#include "type.h"

#ifdef __cplusplus
extern "C" {
#endif




/* 协程轮休后返回状态 */
#define PRO_WAITING                         0                                   //等待
#define PRO_YIELDED                         1                                   //执行完成，返回挂起
#define PRO_EXITED                          2                                   //协程退出，协程自己申请退出
#define PRO_ENDED                           3                                   //协程执行结束，执行到了while外面


/* ----- 协程处理相关的宏定义 ----- */
#define LC_INIT(s)                          s = 0                               //LC初始化
#define LC_RESUME(s)                        switch(s) { case 0:                 //LC恢复
#define LC_SET(s)                           s = __LINE__; case __LINE__:        //LC设置
#define LC_END(s)                           }                                   //LC结束

/* 用于实现ETF_PROCESS_BEGIN的宏定义 */
/* PT_YIELD_FLAG为生产者标志，因为协程是基于事件处理，进入这里面就产生了一个事件，标记
 * 一个生产者标志，执行完成后会因while清除这个标志，防止重复处理。 */
#define PROCESS_BEGIN(pt)                   { etf_uint8_t PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)

/* 用于实现ETF_PROCESS_END的宏定义 */
/* LC_END((pt)->lc)为PROCESS_BEGIN宏定义中LC_RESUME(s)的switch匹配的'}'，清除生产者、协
 * 程保存行号清零恢复默认、返回协程结束退出状态 */
#define PROCESS_END(pt)                     LC_END((pt)->lc); PT_YIELD_FLAG = 0;LC_INIT((pt)->lc); return PRO_ENDED;}

/* 用于实现ETF_PROCESS_WAIT_EVENT_UNTIL的宏定义 */
#define PROCESS_YIELD_UNTIL(co_pt, cond)           \
    do {						                \
        PT_YIELD_FLAG           = 0;            \
        LC_SET((co_pt)->lc);				    \
        if((PT_YIELD_FLAG == 0) || !(cond)){    \
          return PRO_YIELDED;			        \
        }						                \
    }while(0)


/* 定义一个协程的宏。(定义任务处理函数的时候通过这个宏定义来定义函数的开始入口) */
#define ETF_PROCESS(name, co_ev, co_data)       \
    static etf_uint8_t co_process_##name(struct pt * co_pt, coroutine_event_t co_ev, coroutine_data_t co_data)
    
/* 获取协程任务完整名的宏定义。(定义任务处理函数的时候使用了CO_PROCESS宏定义进行了封装，所以在使用完整的任务名时需要这个宏来转换一下)*/
#define ETF_PROCESS_NAME_GET(name)          co_process_##name

/* 协程处理任务开始标志 */
#define ETF_PROCESS_BEGIN()                 PROCESS_BEGIN(co_pt)
/* 协程任务处理结束标志 */
#define ETF_PROCESS_END()                   PROCESS_END(co_pt)
/* 事件等待标志 */
#define ETF_PROCESS_WAIT_EVENT_UNTIL(c)     PROCESS_YIELD_UNTIL(co_pt, c)

/* ----- 协程用到的基础类型 ----- */
typedef etf_uint16_t                        lc_t;                               //行号类型
typedef etf_uint16_t                        coroutine_event_t;                  //协程事件类型
typedef void *                              coroutine_data_t;                   //协程数据类型
typedef etf_int8_t                          coroutine_num_events_t;             //协程事件数量

enum etf_coroutine_state_type {
    ETF_PROCESS_STATE_NONE              = 0,                                    //挂起，未添加到链表，或在链表中但不接受任何事件
    ETF_PROCESS_STATE_RUNNING,                                                  //运行，运行，在链表中等待事件
    ETF_PROCESS_STATE_CALLED                                                    //正在被调用，正在运行处理事件
};

struct pt{
    lc_t                                    lc;
};

/* 协程控制块 */
struct etf_co_tcb{

    /* 对象继承，必须为第一个成员 */
    struct etf_object                       parent;
    /* 协程处理函数指针 */
    etf_uint8_t                             (*coroutine)(struct pt * const co_pt, coroutine_event_t co_ev, coroutine_data_t co_data);
    /* 协程需要存储的信息。(当前只保存行号) */
    struct pt                               pt;
    /* 协程状态 */
    enum etf_coroutine_state_type           state;
    /* 协程轮询请求 */
    etf_uint8_t                             needspoll;
    /* 协程轮询事件传递的数据 */
    coroutine_data_t                        data;
};

typedef struct etf_co_tcb *                 etf_co_tcb_t;

extern struct etf_co_tcb *                  etf_process_current;

void etf_coroutine_module_init(void);
struct etf_co_tcb * etf_coroutine_init(struct etf_co_tcb * const co_tcb, const char *name, etf_uint8_t (*coroutine)(struct pt * co_pt, coroutine_event_t co_ev, coroutine_data_t co_data));
etf_err_t etf_coroutine_unregister(struct etf_co_tcb * const co_tcb);
etf_err_t etf_coroutine_startup(struct etf_co_tcb * const co_tcb);
etf_err_t etf_coroutine_suspend(struct etf_co_tcb * const co_tcb);
etf_err_t etf_coroutine_resume(struct etf_co_tcb * const co_tcb);
void etf_poll_requested(struct etf_co_tcb * const co_tcb, coroutine_data_t co_data);
void call_process(struct etf_co_tcb * const co_tcb, coroutine_event_t co_ev, coroutine_data_t co_data);
etf_uint32_t etf_coroutine_run(void);

#ifdef __cplusplus
}
#endif
 
#endif
 

